package datastructure.blockqueue;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 基于数组的有界阻塞队列
 * @param <E> 队列中元素的类型
 */
public class ArrayBlockingQueue<E> {
    // 存储元素的数组
    private final Object[] items;
    // 队列容量
    private final int capacity;
    // 头指针（指向队头元素）
    private int head;
    // 尾指针（指向队尾下一个空位）
    private int tail;
    // 队列中元素数量
    private int size;
    // 保证线程安全的锁
    private final ReentrantLock lock;
    // 条件变量：队列不空（用于唤醒出队线程）
    private final Condition notEmpty;
    // 条件变量：队列不满（用于唤醒入队线程）
    private final Condition notFull;


    /**
     * 构造函数：初始化队列容量和锁
     * @param capacity 队列最大容量
     */
    public ArrayBlockingQueue(int capacity) {
        if (capacity <= 0) {
            throw new IllegalArgumentException("容量必须为正数：" + capacity);
        }
        this.capacity = capacity;
        this.items = new Object[capacity];
        this.lock = new ReentrantLock();
        this.notEmpty = lock.newCondition(); // 队列不空的条件
        this.notFull = lock.newCondition();  // 队列不满的条件
    }


    /**
     * 入队操作：队列满时阻塞
     * @param e 入队元素（不能为null）
     * @throws InterruptedException 线程被中断时抛出
     */
    public void put(E e) throws InterruptedException {
        if (e == null) {
            throw new NullPointerException("元素不能为null");
        }

        // 获取锁（允许被中断）
        lock.lockInterruptibly();
        try {
            // 队列满时阻塞（用while防虚假唤醒）
            while (size == capacity) {
                notFull.await(); // 释放锁，进入等待状态
            }

            // 插入元素到队尾
            items[tail] = e;
            // 尾指针后移（循环数组：超出容量时回到0）
            tail = (tail + 1) % capacity;
            size++;

            // 唤醒可能阻塞的出队线程（队列从空→非空）
            notEmpty.signal();
        } finally {
            // 释放锁
            lock.unlock();
        }
    }


    /**
     * 出队操作：队列空时阻塞
     * @return 队头元素
     * @throws InterruptedException 线程被中断时抛出
     */
    @SuppressWarnings("unchecked")
    public E take() throws InterruptedException {
        // 获取锁（允许被中断）
        lock.lockInterruptibly();
        try {
            // 队列空时阻塞（用while防虚假唤醒）
            while (size == 0) {
                notEmpty.await(); // 释放锁，进入等待状态
            }

            // 取出队头元素
            E result = (E) items[head];
            // 头指针后移（循环数组）
            head = (head + 1) % capacity;
            size--;

            // 唤醒可能阻塞的入队线程（队列从满→非满）
            notFull.signal();
            return result;
        } finally {
            // 释放锁
            lock.unlock();
        }
    }


    /**
     * 获取当前队列元素数量
     * @return 元素数量
     */
    public int size() {
        lock.lock();
        try {
            return size;
        } finally {
            lock.unlock();
        }
    }


    /**
     * 检查队列是否为空
     * @return 空返回true，否则false
     */
    public boolean isEmpty() {
        lock.lock();
        try {
            return size == 0;
        } finally {
            lock.unlock();
        }
    }
}